package  
{
  import flash.utils.Dictionary;
  import mge.StringUtils;
  import mge.Utils;
	/**
   * ...
   * @author ivan
   */
  public class AnagramUtil 
  {
    //[Embed(source='../assets/clean_list/english.txt',mimeType="application/octet-stream")]
    [Embed(source='../assets/clean_list/spanish.txt',mimeType="application/octet-stream")]
    private var rTextFile: Class;
    
    private var wordList:Vector.<String>;
    private const allLetters:Array = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', /*'Á', 'É', 'Í', 'Ó', 'Ú',*/ 'Ñ'];
    
    public function AnagramUtil() 
    {
      wordList = buildWords();
    }
    
    public function exists(word:String):Boolean
    {
      var idx:int = wordList.indexOf(word, 0);
      return idx != -1;
    }
    
        
    /*
     * Returns a vector with all words that can be build with given letters.
     * */
    public function wordsWithLetters(letters:Vector.<String>):Vector.<String>
    {
      var others:Vector.<String> = invert(letters);
      
      // Remove words with other words.
      var words:Vector.<String> = wordList.concat();
        
      for (var i:int = 0; i < others.length; i++)
      {
        letter = others[i];
        words = words.filter(dontHaveLetter, this);
      }
      
      return words;
    }
    
    /*
     * Same as wordsWithLetters. Use of letters multiple times is not allowed.
     * */
    public function wordsWithLettersNoRepetition(letters:Vector.<String>):Vector.<String>
    {
      // Keep count of each letter
      var reps:Dictionary = new Dictionary;
      for (var i:int = 0; i < letters.length; i++)
        reps[letters[i]] = 0;
      for (i = 0; i < letters.length; i++)
        reps[letters[i]]++;
      
      // Build words.
      var words:Vector.<String>  = wordsWithLetters(letters);
      
      // Discard those word with more letter repetitions than letters in parameter 1.
      for (i = 0; i < words.length; i++)
      {
        var word:String = words[i];
        for (var j:int = 0; j < word.length; j++)
        {
          var c:String = word.charAt(j);
          if (StringUtils.countOf(word, c) > reps[c])
          {
            words.splice(i--, 1);
            break;
          }
        }
      }
      
      return words;
    }
    
    
    
    /*
     * Given a vector of letters, returns all letters in abecedary that are not included in letters.
     * */
    private function invert(letters:Vector.<String>):Vector.<String>
    {
      var others:Vector.<String> = new Vector.<String>();
      for (var i:int = 0; i < allLetters.length; i++)
        others.push(allLetters[i]);
        
      for (i = 0; i < letters.length; i++)
      {
        letter = letters[i];
        others = others.filter(dontHaveLetter, this);
      }
      
      return others;
    }
    
    /*
     * Returns the list with all words in dic.
     * */
    private function buildWords():Vector.<String>
    {
      var text:String = new rTextFile();
      text = text.toUpperCase();
      text = text.replace("\\n", "");
      var array:Array = text.split(/\n/);
      
      var words:Vector.<String>  = new Vector.<String>();
      for (var i:int = 0; i < array.length; i++)
        words.push(array[i]);
      
      // TODO Do this just for spanish (when file is dirty).
      // words = spanishTreatment(words);
      
      words = words.filter(threeOrMore, this);
      
      return words;
    }
    
    // Corrects some stuff for the spanish dict. Temporal.
    private function spanishTreatment(words:Vector.<String>):Vector.<String>
    {
      var treated:Vector.<String> = new Vector.<String>;
      for (var i:int = 0; i < words.length; i++)
      {
        var w:String = words[i];
        //w = StringUtils.remove(w, "*");
        //w = StringUtils.remove(w, "#");
        w = w.replace("*", "");
        w = w.replace("#", "");
        w = w.replace("A\\", "A");
        w = w.replace("E\\", "E");
        w = w.replace("I\\", "I");
        w = w.replace("O\\", "O");
        w = w.replace("U\\", "U");
        w = w.replace("Ñ~", "Ñ");
        
        treated.push(w);
      }
      return treated;
    }
    
    
    // Filters
    private var letter:String;
    private function lessEqualLetters(item:String, index:int, vector:Vector.<String>):Boolean { return item.search(letter) != -1; };
    private function threeOrMore(item:String, index:int, vector:Vector.<String>):Boolean { return (item.length >= 3); }
    private function haveLetter(item:String, index:int, vector:Vector.<String>):Boolean { return item.search(letter) != -1; };
    private function dontHaveLetter(item:String, index:int, vector:Vector.<String>):Boolean { return item.search(letter) == -1; }
    
    public static function longestFirst(a:String, b:String):Number
    {
      if (a.length < b.length) return 1;
      if (a.length > b.length) return -1;
      return 0;
    }

    public function pickUpRandomLetter():String
    {
      // var f:Dictionary = getEnglishFrequencyDictionary();
      var f:Dictionary = getSpanishFrequencyDictionary();
      var r:Number = Math.random() * 100;
      var total:Number = 0;
      for (var key:Object in f)
      {
        total += f[key];
        if (r < total)
          return key as String;
      }
      return "";
    }
    
    // http://en.wikipedia.org/wiki/Letter_frequency
    private function getEnglishFrequencyDictionary():Dictionary
    {
      var f:Dictionary = new Dictionary;
      f['A'] = 8.167
      f['B'] = 1.492
      f['C'] = 2.782
      f['D'] = 4.253
      f['E'] = 12.702
      f['F'] = 2.228
      f['G'] = 2.015
      f['H'] = 6.094
      f['I'] = 6.966
      f['J'] = 0.153
      f['K'] = 0.772
      f['L'] = 4.025
      f['M'] = 2.406
      f['N'] = 6.749
      f['O'] = 7.507
      f['P'] = 1.929
      f['Q'] = 0.095
      f['R'] = 5.987
      f['S'] = 6.327
      f['T'] = 9.056
      f['U'] = 2.758
      f['V'] = 0.978
      f['W'] = 2.360
      f['X'] = 0.150
      f['Y'] = 1.974
      f['Z'] = 0.074
      return f;
    }
    
    private function getSpanishFrequencyDictionary():Dictionary
    {
      var f:Dictionary = new Dictionary;
      f['A'] = 12.53
      f['B'] = 1.42
      f['C'] = 4.68
      f['D'] = 5.86
      f['E'] = 13.68
      f['F'] = 0.69
      f['G'] = 1.01
      f['H'] = 0.70
      f['I'] = 6.25
      f['J'] = 0.44
      f['K'] = 0.01
      f['L'] = 4.97
      f['M'] = 3.15
      f['N'] = 6.71
      f['O'] = 8.68
      f['P'] = 2.51
      f['Q'] = 0.88
      f['R'] = 6.87
      f['S'] = 7.98
      f['T'] = 4.63
      f['U'] = 3.93
      f['V'] = 0.90
      f['W'] = 0.02
      f['X'] = 0.22
      f['Y'] = 0.90
      f['Z'] = 0.52
      return f;
    }
    
  }

}